package me.zhangsanfeng.gpss.common.utils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.RandomAccess;
import java.util.Set;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Splitter;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import me.zhangsanfeng.gpss.common.entity.BaseException;

public class CollectionUtil{
    /**
     * 集合过滤
     * @param targetList 主集合
     * @param filterList 从集合
     * @param sourceKey 主集合过滤字段
     * @param isTrue true:白名单 fasle:黑名单
     * @return List<T>
     */
    @SuppressWarnings("rawtypes")
    public static <T,B> List<T> filterList(List<T> targetList,List<B> filterList,String sourceKey,
            String filterKey,boolean isTrue)
    {
        if(filterList.size()==0){
            return targetList;
        }
        String sources[]=sourceKey.split(",");
        String filters[]=filterKey.split(",");
        if(sources.length==filters.length){
            Set<String> filterSet=new HashSet<String>();
            for(Iterator<B> iterator=filterList.iterator();iterator.hasNext();){
                B b=iterator.next();
                String filterString="";
                for(int i=0;i<filters.length;i++){
                    if(b instanceof Map){
                        filterString+=String.valueOf(((Map)b).get(filters[i]));
                    }else{
                        filterString+=String.valueOf(ReflectionUtil.getFieldValue(b,filters[i]));
                    }
                }
                filterSet.add(filterString);
            }
            Collection<T> filterCollection=Collections2.filter(targetList,
                    new Predicate<T>()
            {
                        @Override
                        public boolean apply(T t){
                            String sourceValue="";
                            for(int i=0;i<sources.length;i++){
                                if(t instanceof Map){
                                    sourceValue+=String.valueOf(((Map)t).get(sources[i]));
                                }else{
                                    sourceValue+=String.valueOf(ReflectionUtil.getFieldValue(t,sources[i]));
                                }
                            }
                            if(filterSet.contains(sourceValue)){
                                return isTrue;
                            }else{
                                return !isTrue;
                            }
                        }
                    });
            return Lists.newArrayList(filterCollection);
        }else{
            throw new BaseException("sourceKey和filterKey长度不匹配");
        }
    }

    public static <T,B> List<T> filterList(List<T> targetList,List<B> filterList,String sourceKey,
            String filterKey)
    {
        return filterList(targetList,filterList,sourceKey,filterKey,true);
    }

    /**
     * 集合左关联
     * @param leftList 主集合
     * @param rightList 从集合
     * @param leftKey 主集合关联字段 key1,key2,key3
     * @param rightKey 从集合关联字段 key1,key2,key3
     * @param rightColumns 从集合返回字段 key1=0,key2=0,key3=3
     * @return List<Map<String,Object>>
     */
    public static <T,B> List<Map<String,Object>> leftJoinList(List<T> leftList,List<B> rightList,
            String leftKey,String rightKey,String rightColumns)
    {
        return join(leftList,rightList,leftKey,rightKey,rightColumns,"left");
    }

    /**
     * 集合关联
     * @param leftList 主集合
     * @param rightList 从集合
     * @param leftKey 主集合关联字段 key1,key2,key3
     * @param rightKey 从集合关联字段 key1,key2,key3
     * @param rightColumns 从集合返回字段 key1=0,key2=0,key3=3
     * @return List<Map<String,Object>>
     */
    public static <T,B> List<Map<String,Object>> joinList(List<T> leftList,List<B> rightList,String leftKey,
            String rightKey,String rightColumns)
    {
        return join(leftList,rightList,leftKey,rightKey,rightColumns,"join");
    }

    /**
     * 集合关联
     * @param leftList 主集合
     * @param rightList 从集合
     * @param leftKey 主集合关联字段 key1,key2,key3
     * @param rightKey 从集合关联字段 key1,key2,key3
     * @param rightColumns 从集合返回字段 key1=0,key2=0,key3=3
     * @return List<Map<String,Object>>
     */
    @SuppressWarnings({"rawtypes","unchecked"})
    private static <T,B> List<Map<String,Object>> join(List<T> leftList,List<B> rightList,String leftKey,
            String rightKey,String rightColumns,String type)
    {
        String liftKeys[]=leftKey.split(",");
        Map<String,B> rightMap=mapObject(rightList,rightKey);
        Map<String,String> defaultMap=Splitter.on(",").withKeyValueSeparator("=").split(rightColumns);
        List<Map<String,Object>> list=Lists.newArrayList();
        for(Iterator<T> iterator=leftList.iterator();iterator.hasNext();){
            T t=iterator.next();
            Map<String,Object> map=new HashMap<String,Object>();
            if(t instanceof Map){
                map=((Map)t);
            }else{
                map=MapUtils.beanToMap(t);
            }
            String leftValue="";
            for(int i=0;i<liftKeys.length;i++){
                leftValue+=String.valueOf(map.get(liftKeys[i]));
            }
            B b=rightMap.get(leftValue);
            map.putAll(defaultMap);
            if(b!=null){
                Map newMap=new HashMap();
                if(b instanceof Map){
                    newMap=(Map)b;
                }else{
                    newMap=MapUtils.beanToMap(b);
                }
                newMap=MapUtils.filterMapKey(newMap,rightColumns);
                map.putAll(newMap);
                if(type.equals("join")){
                    list.add(map);
                }
            }
            if(type.equals("left")){
                list.add(map);
            }
        }
        return list;
    }

    /**
     * 集合构建树形
     * @param list 主集合
     * @param treeFields 树形描述字段 id=orgUnitId,label=unitName,treeId=relOrgUnitId,child=children
     * @param treeRoot 树形根节点id值
     * @return Map<String,Object>
     */
    @SuppressWarnings({"unchecked","rawtypes"})
    public static <T> Map<String,Object> listToTree(List<T> list,String treeFields,String treeRoot){
        Map<String,String> treeFieldsMap=Splitter.on(",").withKeyValueSeparator("=").split(treeFields);
        String idKey=treeFieldsMap.get("id");
        String labelKey=treeFieldsMap.get("label");
        String parentKey=treeFieldsMap.get("treeId");
        String children=treeFieldsMap.get("child");
        T root=CollectionUtil.findInList(list,idKey+"="+treeRoot);
        Map<String,Collection<T>> mapList=mapList(list,parentKey);
        Collection<T> rootList=mapList.get(treeRoot);
        if(DataUtil.isEmpty(rootList)){
            rootList=new ArrayList<T>();
        }
        Map<String,Object> treeMap=new HashMap<String,Object>();
        for(Iterator<T> iterator=rootList.iterator();iterator.hasNext();){
            T t=iterator.next();
            Map newMap=new HashMap();
            if(t instanceof Map){
                newMap=(Map)t;
            }else{
                newMap=MapUtils.beanToMap(t);
            }
            String keyValue=String.valueOf(newMap.get(idKey));
            if(treeRoot.equals(keyValue)){
                iterator.remove();
            }
        }
        Map newMap=new HashMap();
        if(root instanceof Map){
            newMap=(Map)root;
        }else{
            newMap=MapUtils.beanToMap(root);
        }
        treeMap.putAll(newMap);
        treeMap.put("id",newMap.get(idKey));
        treeMap.put("label",newMap.get(labelKey));
        treeMap.put("treeId","");
        treeMap.put("treeLabel","");
        String keyValue=String.valueOf(treeMap.get(idKey));
        String labelValue=String.valueOf(treeMap.get(labelKey));
        treeMap.put(children,buildTree(rootList,mapList,idKey,labelKey,keyValue,labelValue,children));
        return treeMap;
    }

    @SuppressWarnings("rawtypes")
    public static <T> Map<String,Collection<T>> mapList(List<T> list,String mapKey){
        String mapKeys[]=mapKey.split(",");
        Multimap<String,T> treeMap=ArrayListMultimap.create();
        for(Iterator<T> iterator=list.iterator();iterator.hasNext();){
            T t=iterator.next();
            String keyValue="";
            for(int i=0;i<mapKeys.length;i++){
                if(t instanceof Map){
                    keyValue+=String.valueOf(((Map)t).get(mapKeys[i]));
                }else{
                    keyValue+=String.valueOf(ReflectionUtil.getFieldValue(t,mapKeys[i]));
                }
            }
            treeMap.put(keyValue,t);
        }
        return treeMap.asMap();
    }

    public static <T> Map<String,T> mapObject(List<T> list,String mapKey){
        String mapKeys[]=mapKey.split(",");
        Map<String,T> map=Maps.uniqueIndex(list.iterator(),new Function<T,String>(){
            @SuppressWarnings("rawtypes")
            @Override
            public String apply(T input){
                String keyValue="";
                for(int i=0;i<mapKeys.length;i++){
                    if(input instanceof Map){
                        keyValue+=String.valueOf(((Map)input).get(mapKeys[i]));
                    }else{
                        keyValue+=String.valueOf(ReflectionUtil.getFieldValue(input,mapKeys[i]));
                    }
                }
                return keyValue;
            }
        });
        return map;
    }

    @SuppressWarnings({"unchecked","rawtypes"})
    private static <T> List<Map<String,Object>> buildTree(Collection<T> list,
            Map<String,Collection<T>> maplist,String idKey,String labelKey,String parentId,
            String parentLabel,String children)
    {
        List<Map<String,Object>> newList=new ArrayList<Map<String,Object>>();
        for(Iterator<T> iterator=list.iterator();iterator.hasNext();){
            T t=iterator.next();
            Map newMap=new HashMap();
            if(t instanceof Map){
                newMap=(Map)t;
            }else{
                newMap=MapUtils.beanToMap(t);
            }
            String keyValue=String.valueOf(newMap.get(idKey));
            String labelValue=String.valueOf(newMap.get(labelKey));
            newMap.put("id",keyValue);
            newMap.put("value",keyValue);
            newMap.put("label",labelValue);
            newMap.put("treeId",parentId);
            newMap.put("treeLabel",parentLabel);
            Collection<T> childList=maplist.get(keyValue);
            if(childList!=null){
                newMap.put(children,buildTree(childList,maplist,idKey,labelKey,keyValue,labelValue,children));
            }
            newList.add(newMap);
        }
        return newList;
    }

    /**
     * 集合排序
     * @param list 主集合
     * @param key 集合中排序的字段名
     * @param order 顺序 升序 asc 降序 desc
     * @return
     */
    public static <T> void orderList(List<T> list,final String key,final String order){
        Collections.sort(list,new Comparator<T>(){
            @SuppressWarnings("rawtypes")
            @Override
            public int compare(T o1,T o2){
                Map map1=new HashMap();
                Map map2=new HashMap();
                if(o1 instanceof Map){
                    map1=(Map)o1;
                    map2=(Map)o2;
                }else{
                    map1=MapUtils.beanToMap(o1);
                    map2=MapUtils.beanToMap(o2);
                }
                if(order.equals("desc")){
                    return compareValue(map2,new String[]{key,String.valueOf(map1.get(key))});
                }else{
                    return compareValue(map1,new String[]{key,String.valueOf(map2.get(key))});
                }
            }
        });
    }

    /**
     * 集合查找
     * @param list 主集合
     * @param keyValue 集合中查找的字段 key=value
     * @return
     */
    public static <T> T findInList(List<T> list,String keyValue){
        String keys[]=keyValue.split("=");
        int index=0;
        orderList(list,keys[0],"asc");
        if(list instanceof RandomAccess||list.size()<5000)
            index=indexedBinarySearch(list,keys);
        else
            index=iteratorBinarySearch(list,keys);
        return list.get(index);
    }

    private static <T> int indexedBinarySearch(List<T> l,String keys[]){
        int low=0;
        int high=l.size()-1;
        while(low<=high){
            int mid=(low+high)>>>1;
            T midVal=l.get(mid);
            int cmp=compareValue(midVal,keys);
            if(cmp<0)
                low=mid+1;
            else if(cmp>0)
                high=mid-1;
            else
                return mid; // key found
        }
        return -(low+1); // key not found
    }

    private static <T> int iteratorBinarySearch(List<T> l,String keys[]){
        int low=0;
        int high=l.size()-1;
        ListIterator<? extends T> i=l.listIterator();
        while(low<=high){
            int mid=(low+high)>>>1;
            T midVal=get(i,mid);
            int cmp=compareValue(midVal,keys);
            if(cmp<0)
                low=mid+1;
            else if(cmp>0)
                high=mid-1;
            else
                return mid; // key found
        }
        return -(low+1); // key not found
    }

    private static <T> T get(ListIterator<? extends T> i,int index){
        T obj=null;
        int pos=i.nextIndex();
        if(pos<=index){
            do{
                obj=i.next();
            }while(pos++<index);
        }else{
            do{
                obj=i.previous();
            }while(--pos>index);
        }
        return obj;
    }

    @SuppressWarnings("rawtypes")
    private static int compareValue(Object o1,String keys[]){
        Map map1=new HashMap();
        if(o1 instanceof Map){
            map1=(Map)o1;
        }else{
            map1=MapUtils.beanToMap(o1);
        }
        String o1String=String.valueOf(map1.get(keys[0]));
        String o2String=String.valueOf(keys[1]);
        if(ValidateUtils.Number(o1String)&&ValidateUtils.Number(o2String)){
            long o1Value=Long.valueOf(o1String);
            long o2Value=Long.valueOf(o2String);
            if(o1Value<o2Value){
                return -1;
            }else if(o1Value>o2Value){
                return 1;
            }else{
                return 0;
            }
        }else{
            return o1String.compareTo(o2String);
        }
    }

    public static <T> Map<String,Object> pageList(List<T> list,int pageSize,int pageNum){
        int dataSize=list.size();
        Map<String,Object> map=new HashMap<String,Object>();
        map.put("count",dataSize);
        if(pageSize==0||pageNum==0||DataUtil.isEmpty(list)){
            map.put("page",list);
            return map;
        }
        int step=dataSize%pageSize==0 ? dataSize/pageSize : dataSize/pageSize+1;
        if(step==pageNum){
            map.put("page",list.subList((pageNum-1)*pageSize,(pageNum-1)*pageSize+dataSize%pageSize));
        }else{
            map.put("page",list.subList((pageNum-1)*pageSize,(pageNum-1)*pageSize+pageSize));
        }
        return map;
    }
}